package ar.edu.utn.frba.tacs.warnes;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import ar.edu.utn.frba.tacs.warnes.excepciones.NoPuedoVenderPiezaDisponibleException;
import ar.edu.utn.frba.tacs.warnes.excepciones.SoyUnPedidoCanceladoException;
import ar.edu.utn.frba.tacs.warnes.excepciones.SoyUnPedidoVendidoException;
import ar.edu.utn.frba.tacs.warnes.excepciones.YaEstaVendidaException;
import ar.edu.utn.frba.tacs.warnes.pedido.Pedido;
import ar.edu.utn.frba.tacs.warnes.pieza.Pieza;
import ar.edu.utn.frba.tacs.warnes.pieza.PiezaDisponibleState;
import ar.edu.utn.frba.tacs.warnes.pieza.PiezaVendidaState;
import ar.edu.utn.frba.tacs.warnes.utils.ContenedorWarnes;

public class PedidosTestCase {
	private ContenedorWarnes contenedor;
	private Pieza pieza;
	private Pieza pieza2;
	private Pieza pieza3;

	@Before
	public void inicializaciones() {
		this.contenedor = ContenedorWarnes.getInstance();
		this.pieza = this.contenedor.creaUnaPieza("Llanta");
		this.pieza2 = this.contenedor.creaUnaPieza("Radio");
		this.pieza3 = this.contenedor.creaUnaPieza("Parlante");
	}

	@After
	public void limpiarContenedor() {
		this.contenedor.limpiate();
	}
	
	@Test
	public void testNuevoPedido(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		
		assertTrue(pedido.tienePieza(this.pieza));
		assertTrue(pedido.tienePieza(this.pieza2));
		assertFalse(pedido.tienePieza(this.pieza3));
		assertEquals(2,pedido.getPiezas().size());
	}
	
	/**
	 * Testea el estado de las piezas de un pedido reservado
	 */
	@Test
	public void testPedidoEnReserva(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		@SuppressWarnings("unused")
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		
		assertTrue(this.pieza.estaReservada());
		assertTrue(this.pieza2.estaReservada());
		assertTrue(this.pieza3.estaDisponible());
	}
	
	/**
	 * Testea el estado de las piezas de un pedido vendido
	 */
	@Test
	public void testPedidoVendido(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.efectivizar();
		assertTrue(this.pieza.estaVendida());
		assertTrue(this.pieza2.estaVendida());
		assertTrue(this.pieza3.estaDisponible());
	}
	
	/**
	 * Testea el estado de las piezas de un pedido cancelado
	 */
	@Test
	public void testPedidoCancelado(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.cancelar();
		assertTrue(this.pieza.estaDisponible());
		assertTrue(this.pieza2.estaDisponible());
		assertTrue(this.pieza3.estaDisponible());
	}
	
	/**
	 * Testea que no se pueda vender un pedido con una pieza disponible
	 * (en la practica no deberia darse un caso como este)
	 */
	@Test(expected = NoPuedoVenderPiezaDisponibleException.class)
	public void testVenderUnPedidoConUnaPiezaDisponible() {
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		this.pieza.cambiarEstado(PiezaDisponibleState.getInstance());
		pedido.efectivizar();
	}

	/**
	 * Testea que no se pueda vender un pedido con una pieza ya vendida
	 * (en la practica no deberia darse un caso como este)
	 */
	@Test(expected = YaEstaVendidaException.class)
	public void testVenderUnaPiezaVendida() {
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		this.pieza.cambiarEstado(PiezaVendidaState.getInstance());
		pedido.efectivizar();
	}
	
	/**
	 * Testea que la venta del pedido tenga la cantidad correcta
	 */
	@Test
	public void testPedidoVendidoCantidadPiezas(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.efectivizar();
		assertEquals(2,pedido.getCantidadPiezas().intValue());
	}	
	
	/**
	 * Testea que la reserva del pedido tenga la cantidad correcta
	 */
	@Test
	public void testPedidoReservadoCantidadPiezas(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);piezas.add(this.pieza3);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		assertEquals(3,pedido.getCantidadPiezas().intValue());
	}
	
	/**
	 * Testea que el pedido cancelado no pueda pedirle la cantidad de piezas
	 */
	@Test(expected = SoyUnPedidoCanceladoException.class)
	public void testPedidoCanceladoCantidadPiezas(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.cancelar();
		assertEquals(123,pedido.getCantidadPiezas().intValue());
	}
	
	/**
	 * Testea que el pedido cancelado no pueda agregar mas piezas
	 */
	@Test(expected = SoyUnPedidoCanceladoException.class)
	public void testPedidoCanceladoAgregarPieza(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.cancelar();
		pedido.agregarPieza(this.pieza3);
	}
	
	/**
	 * Testea que el pedido reservado pueda agregar mas piezas
	 */
	@Test
	public void testPedidoReservadoAgregarPieza(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		assertEquals(2,pedido.getCantidadPiezas().intValue());
		pedido.agregarPieza(this.pieza3);
		assertEquals(3,pedido.getCantidadPiezas().intValue());
	}
	
	/**
	 * Testea que el pedido vendido no pueda agregar mas piezas
	 */
	@Test(expected = SoyUnPedidoVendidoException.class)
	public void testPedidoVendidoAgregarPieza(){
		List<Pieza> piezas = new ArrayList<Pieza>();
		piezas.add(this.pieza);piezas.add(this.pieza2);
		Pedido pedido = this.contenedor.crearUnPedido(piezas);
		pedido.efectivizar();
		pedido.agregarPieza(this.pieza3);
	}
}
